package com.flyduck.mybatis.task;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.Date;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * <p></p>
 * Spring Task 文档：https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling
 *
 * @author flyduck 2020/12/28 20:47
 * @version V1.0
 * @modify by user: LiuHui 2020/12/28
 * @modify by reason:{原因}
 **/
@Configuration
@EnableScheduling
@EnableAsync
public class AppTask {

    /**
     * 自定义任务执行线程池
     * 默认的线程池为1个线程 https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-task-namespace-scheduler
     *
     * @author flyduck
     * @date 2020/12/28 22:15
     * @param []
     * @return org.springframework.scheduling.TaskScheduler
    */
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 配置线程池大小，根据任务数量定制
        taskScheduler.setPoolSize(10);
        // 线程名称前缀
        taskScheduler.setThreadNamePrefix("flyduck-task-scheduler-thread-");
        // 线程池关闭前最大等待时间，确保最后一定关闭
        taskScheduler.setAwaitTerminationSeconds(60);
        // 线程池关闭时等待所有任务完成
        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        // 线程池对拒绝任务的处理策略
        taskScheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        return taskScheduler;
    }

    /**
     * 自定义异步任务线程池
     * 官方文档：https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-task-namespace-executor
     *
     * @author flyduck
     * @date 2020/12/28 22:22
     * @param []
     * @return java.util.concurrent.Executor
    */
    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 配置核心线程数
        executor.setCorePoolSize(10);
        // 配置最大线程数
        executor.setMaxPoolSize(20);
        // 配置缓存队列大小
        executor.setQueueCapacity(100);
        // 空闲线程存活时间
        executor.setKeepAliveSeconds(15);
        // 线程名称前缀
        executor.setThreadNamePrefix("flyduck-task-executor-thread-");
        // 线程池对拒绝任务的处理策略：这里采用了CallerRunsPolicy策略，当线程池没有处理能力的时候，该策略会直接在execute方法的调用线程中运行被拒绝的任务；如果执行程序已关闭，则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 设置线程池中任务的等待时间，如果超过这个时候还没有销毁就强制销毁，以确保应用最后能够被关闭，而不是被没有完成的任务阻塞
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }

    /**
     * 使用fixedDelay的任务
     * fixedDelay表示从上次任务完成之后间隔多久执行
     *
     * @author flyduck
     * @date 2020/12/28 21:53
     * @param []
     * @return void
    */
    @Scheduled(fixedDelay = 1000)
    public void taskA() {
        System.out.println(Thread.currentThread().getName() + " Task A run ..." + new Date().toString());
    }

    /**
     * 使用fixedRate的任务
     * fixedRate表示从上次任务开始后间隔多久执行
     *
     * @author flyduck
     * @date 2020/12/28 21:54
     * @param []
     * @return void
    */
    @Scheduled(fixedRate = 1000)
    public void taskB() {
        System.out.println(Thread.currentThread().getName() + " Task B run ..." + new Date().toString());
    }

    /**
     * 使用cron表达式的任务
     * Cron表达式文档：https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-cron-expression
     *
     * @author flyduck
     * @date 2020/12/28 21:51
     * @param []
     * @return void
    */
    @Scheduled(cron = "*/1 * * * * *")
    public void taskC() {
        System.out.println(Thread.currentThread().getName() + " Task C run ..." + new Date().toString());
    }

    /**
     * 使用fixedRateString的任务
     * fixedRateString示从上次任务开始后间隔多久执行，从配置中获取fixedRateString的值，如果没有配置则设置为1000
     *
     * @author flyduck
     * @date 2020/12/28 22:04
     * @param []
     * @return void
    */
    @Scheduled(fixedRateString = "${project.task.fixed-rate:1000}")
    public void taskD() {
        System.out.println(Thread.currentThread().getName() + " Task D run ..." + new Date().toString());
    }

    /**
     * 使用cron表达式的异步任务
     * Cron表达式文档：https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-cron-expression
     * 从配置中获取cron的值，如果没有配置则设置为 *\/10 * * * * *
     *
     * @author flyduck
     * @date 2020/12/28 22:06
     * @param []
     * @return void
    */
    @Scheduled(cron = "${project.task.cron:*/10 * * * * *}")
    @Async
    public void taskE() {
        System.out.println(Thread.currentThread().getName() + " Task E run ..." + new Date().toString());
    }
}
